package com.substanceofcode.data.midp;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;

import com.substanceofcode.data.FileIOException;
import com.substanceofcode.data.Serializable;

import net.sf.microlog.core.Logger;
import net.sf.microlog.core.LoggerFactory;

import junitj2me.framework.TestCase;

public class RsfsFileTest extends TestCase
{
    private final static Logger LOG = LoggerFactory.getLogger();

    protected void setUp() throws Exception
    {
        FileSystemImpl.resetStaticData();
        FileSystemImpl.getFileSystem().formatFileSystem();
    }

    public static void assertFileContentsEqual( String aFilename, byte[] aFileContents )
    {
        try
        {
            boolean exists = FileSystemImpl.getFileSystem().exists( aFilename );
            assertTrue( "File should now exist", exists );

            InputStream is = FileSystemImpl.getFileSystem().getFile( aFilename );
            assertNotNull( "getFile InputStream not null", is );

            int available = is.available();

            assertEquals( "Bytes available must be as expected", aFileContents.length, available );

            byte[] readBytes = new byte[available];
            is.read( readBytes, 0, available );

            assertEquals( "Bytes read must match", aFileContents, readBytes );
        }
        catch( Exception e )
        {
            fail( "assertFileContentsEqual threw " + e.getMessage() );
        }
    }

    public static class DummyFile implements com.substanceofcode.data.Serializable
    {
        DummyFile( byte[] aData, String aMimeType )
        {
            iData = aData;
            iMimeType = aMimeType;
        }

        public String getMimeType()
        {
            return iMimeType;
        }

        public void serialize( DataOutputStream dos ) throws IOException
        {
            if( null != iData )
            {
                dos.write( iData );
            }
        }

        public void unserialize( DataInputStream dis ) throws IOException
        {
            int available = dis.available();
            iData = new byte[available];
            dis.read( iData );
        }

        byte[] iData;
        String iMimeType;
    }

    private static final String TEST_FILENAME = "file:////somedirectory/another/testfile.txt";

    public void test1()
    {
        LOG.info( "testSaveEmptyFileThrowsException" );

        try
        {
            boolean exists = FileSystemImpl.getFileSystem().exists( TEST_FILENAME );
            assertFalse( "File shouldn't exist yet", exists );

            DummyFile dummyFile = new DummyFile( null, null );

            FileSystemImpl.getFileSystem().saveFile( TEST_FILENAME, dummyFile, true );

            fail( "testSaveEmptyFileThrowsException exception should have been thrown" );
        }
        catch( FileIOException fioe )
        {
            LOG.info( "Expected exception thrown: " + fioe.toString() );
        }
        catch( Exception e )
        {
            fail( e.toString() );
            LOG.info( e.toString() );
        }
    }

    private static final byte[] SHORT_TEST_BYTES = "SomeTestBytes".getBytes();

    public void test2()
    {
        LOG.info( "testSaveNoMimeTypeThrowsException" );

        try
        {
            boolean exists = FileSystemImpl.getFileSystem().exists( TEST_FILENAME );
            assertFalse( "File shouldn't exist yet", exists );

            DummyFile dummyFile = new DummyFile( SHORT_TEST_BYTES, null );

            FileSystemImpl.getFileSystem().saveFile( TEST_FILENAME, dummyFile, true );

            fail( "testSaveNoMimeTypeThrowsException exception should have been thrown" );

        }
        catch( FileIOException fioe )
        {
            LOG.info( "Expected exception thrown: " + fioe.toString() );
        }
        catch( Exception e )
        {
            fail( e.toString() );
            LOG.info( e.toString() );
        }
    }

    private static final String OCTET_STREAM = "application/octet-stream";

    public void test3()
    {
        LOG.info( "testSaveFile" );

        try
        {
            boolean exists = FileSystemImpl.getFileSystem().exists( TEST_FILENAME );
            assertFalse( "File shouldn't exist yet", exists );

            DummyFile dummyFile = new DummyFile( SHORT_TEST_BYTES, OCTET_STREAM );

            FileSystemImpl.getFileSystem().saveFile( TEST_FILENAME, dummyFile, true );

            exists = FileSystemImpl.getFileSystem().exists( TEST_FILENAME );
            assertTrue( "File should now exist", exists );

        }
        catch( Exception e )
        {
            fail( e.toString() );
            LOG.info( e.toString() );
        }
    }

    public void test4()
    {
        LOG.info( "testErrorGetFileInputStreamNotExists" );

        try
        {
            InputStream is = FileSystemImpl.getFileSystem().getFile( TEST_FILENAME );

            fail( "getFile InputStream should fail since file doesn't exist" );
        }
        catch( IOException ioe )
        {
            LOG.debug( "Good!" );
        }

    }

    public void test5()
    {
        LOG.info( "testGetFileInputStream" );

        try
        {
            boolean exists = FileSystemImpl.getFileSystem().exists( TEST_FILENAME );
            assertFalse( "File shouldn't exist yet", exists );

            DummyFile dummyFile = new DummyFile( SHORT_TEST_BYTES, OCTET_STREAM );

            FileSystemImpl.getFileSystem().saveFile( TEST_FILENAME, dummyFile, true );

            exists = FileSystemImpl.getFileSystem().exists( TEST_FILENAME );
            assertTrue( "File should now exist", exists );

            InputStream is = FileSystemImpl.getFileSystem().getFile( TEST_FILENAME );
            assertNotNull( "getFile InputStream not null", is );

        }
        catch( Exception e )
        {
            fail( e.toString() );
            LOG.info( e.toString() );
        }
    }

    public void test6()
    {
        LOG.info( "testSaveThenReadInputStream" );

        try
        {
            boolean exists = FileSystemImpl.getFileSystem().exists( TEST_FILENAME );
            assertFalse( "File shouldn't exist yet", exists );

            DummyFile dummyFile = new DummyFile( SHORT_TEST_BYTES, OCTET_STREAM );

            FileSystemImpl.getFileSystem().saveFile( TEST_FILENAME, dummyFile, true );

            assertFileContentsEqual( TEST_FILENAME, SHORT_TEST_BYTES );
        }
        catch( Exception e )
        {
            fail( e.toString() );
            LOG.info( e.toString() );
        }
    }

    public void test7()
    {
        LOG.info( "testSaveThenResetAllThenReadInputStreamShouldFailSinceNoMimeTypeMeantExceptionThrown" );

        try
        {
            boolean exists = FileSystemImpl.getFileSystem().exists( TEST_FILENAME );
            assertFalse( "File shouldn't exist yet", exists );

            DummyFile dummyFile = new DummyFile( SHORT_TEST_BYTES, null );

            FileSystemImpl.getFileSystem().saveFile( TEST_FILENAME, dummyFile, true );

            fail( "testSaveThenResetAllThenReadInputStreamShouldFailSinceNoMimeTypeMeantExceptionThrown" );
        }
        catch( FileIOException fioe )
        {
            LOG.info( "testSaveThenResetAllThenReadInputStreamShouldFailSinceNoMimeTypeMeantExceptionThrown Expected exception thrown: " + fioe.getMessage() );
        }

        try
        {

            boolean exists = FileSystemImpl.getFileSystem().exists( TEST_FILENAME );
            assertFalse( "File should not now exist, since save failed", exists );
        }
        catch( Exception e )
        {
            fail( e.toString() );
            LOG.info( e.toString() );
        }
    }

    public void test8()
    {
        LOG.info( "testSaveThenResetAllThenReadInputStream" );

        try
        {
            boolean exists = FileSystemImpl.getFileSystem().exists( TEST_FILENAME );
            assertFalse( "File shouldn't exist yet", exists );

            DummyFile dummyFile = new DummyFile( SHORT_TEST_BYTES, OCTET_STREAM );

            FileSystemImpl.getFileSystem().saveFile( TEST_FILENAME, dummyFile, true );

            assertFileContentsEqual( TEST_FILENAME, SHORT_TEST_BYTES );

            // Now ensure we're re-reading everything from flash.
            FileSystemImpl.resetStaticData();

            assertFileContentsEqual( TEST_FILENAME, SHORT_TEST_BYTES );

        }
        catch( Exception e )
        {
            fail( e.toString() );
            LOG.info( e.toString() );
        }
    }

    public void test9()
    {
        LOG.info( "testDeleteFileThatDoesntExistThrowsException" );

        try
        {
            boolean exists = FileSystemImpl.getFileSystem().exists( TEST_FILENAME );
            assertFalse( "File shouldn't exist yet", exists );

            try
            {
                FileSystemImpl.getFileSystem().deleteFile( TEST_FILENAME );
                fail( "deleteFile on file that doesn't exist should throw exception" );

            }
            catch( FileIOException fioe )
            {
                LOG.info( "testDeleteFileThatDoesntExistThrowsException Expected Exception thrown" );
            }
        }
        catch( Exception e )
        {
            fail( e.toString() );
            LOG.info( e.toString() );
        }

    }

    public void test10()
    {
        LOG.info( "testDeleteFile" );

        try
        {
            boolean exists = FileSystemImpl.getFileSystem().exists( TEST_FILENAME );
            assertFalse( "File shouldn't exist yet", exists );

            DummyFile dummyFile = new DummyFile( SHORT_TEST_BYTES, OCTET_STREAM );

            FileSystemImpl.getFileSystem().saveFile( TEST_FILENAME, dummyFile, true );

            exists = FileSystemImpl.getFileSystem().exists( TEST_FILENAME );
            assertTrue( "File should now exist", exists );

            FileSystemImpl.getFileSystem().deleteFile( TEST_FILENAME );

            exists = FileSystemImpl.getFileSystem().exists( TEST_FILENAME );
            assertFalse( "File should now NOT exist", exists );

            try
            {
                FileSystemImpl.getFileSystem().deleteFile( TEST_FILENAME );
                fail( "deleteFile on already deleted file should throw exception" );

            }
            catch( FileIOException fioe )
            {
                LOG.info( "testDeleteFileThatDoesntExistThrowsException Expected Exception thrown" );
            }

            FileSystemImpl.resetStaticData();

            exists = FileSystemImpl.getFileSystem().exists( TEST_FILENAME );
            assertFalse( "File should now still NOT exist even after resetStaticData", exists );

            try
            {
                FileSystemImpl.getFileSystem().deleteFile( TEST_FILENAME );
                fail( "deleteFile on already deleted file should throw exception" );

            }
            catch( FileIOException fioe )
            {
                LOG.info( "testDeleteFileThatDoesntExistThrowsException Expected Exception thrown" );
            }

        }
        catch( Exception e )
        {
            fail( e.toString() );
            LOG.info( e.toString() );
        }
    }

    protected int getNumberOfImplementedTestMethods()
    {
        return 10;
    }

}
